using System;
using System.Collections.Generic;
using ValidationFramework.Reflection;

namespace ValidationFramework
{
    /// <summary>
    /// Provides an in memory cache of <see cref="MethodDescriptor"/>s.
    /// </summary>
    /// <example>
    /// <code source="Examples\ExampleLibraryCSharp\Reflection\MethodCacheExample.cs" title="The following example shows how to programmatically add validation Rules to a method." lang="cs" region="Example"/>
    /// <code source="Examples\ExampleLibraryVB\Reflection\MethodCacheExample.vb" title="The following example shows how to programmatically add validation Rules to a method." lang="vbnet" region="Example"/>
    /// </example>
    public class MethodPolicyRepository
    {
        // --- Fields

		private Dictionary<MethodKey, MethodPolicy> _methodPolicyDictionary;
		private IValidationPolicyFactory _vpFactory;

		public void AddParameterRule(ParameterKey key, Rule rule, RuleScope scope)
		{
			var methodPolicy = GetOrCreateMethodPolicy(key.MethodKey);
			var paramPolicy = methodPolicy.GetOrCreateParameterPolicy(key);
			paramPolicy.AddRule(rule, scope);
		}
        /// <summary>
		/// Initializes a new instance of the MethodPolicyCache class.
		/// </summary>
		/// <param name="vpFactory"></param>
		public MethodPolicyRepository(IValidationPolicyFactory vpFactory)
		{
			_methodPolicyDictionary = new Dictionary<MethodKey, MethodPolicy>();

			_vpFactory = vpFactory;
		}

		/// <summary>
		/// Initializes a new instance of the MethodPolicyCache class.
		/// </summary>
		/// <param name="vpFactory"></param>
		public MethodPolicyRepository()
		{

			_methodPolicyDictionary = new Dictionary<MethodKey, MethodPolicy>();

			_vpFactory = new ValidationPolicyFactory(new ReflectionCache());
		}

		// --- Methods

        public void Clear()
        {
			_methodPolicyDictionary.Clear();
        }

		public MethodPolicy GetOrCreateMethodPolicy(MethodKey key)
		{
			MethodPolicy policy;
			if (!_methodPolicyDictionary.TryGetValue(key, out policy))
			{
				policy = new MethodPolicy(_vpFactory);
				_methodPolicyDictionary.Add(key, policy);
			}
			return policy;
		}

		public IValidationPolicy GetParameterPolicy(ParameterKey key)
		{
			var methodPolicy = GetOrCreateMethodPolicy(key.MethodKey);
			return methodPolicy.GetOrCreateParameterPolicy(key);
		}
    }
}